#pragma once

#include <iostream>
#include <string>
#include <vector>
#include <memory>
#include <sstream>
#include <fstream>
#include <functional>
#include <unordered_map>
#include <stdexcept>
#include "Log.hpp"

// 定义了HTTP相关的常量，例如换行符、请求头分隔符、网站根目录、默认首页、HTTP版本等
static const std::string sep = "\r\n";               // 换行符（CRLF）
static const std::string header_sep = ": ";          // 请求头字段的分隔符
static const std::string wwwroot = "wwwroot";        // 网站的根目录
static const std::string homepage = "index.html";    // 默认首页文件
static const std::string httpversion = "HTTP/1.0";   // 默认HTTP版本
static const std::string space = " ";                // 空格分隔符
static const std::string filesuffixsep = ".";        // 文件后缀分隔符
static const std::string args_sep = "?";             // URL参数分隔符

class HttpRequest;
class HttpResponse;

using func_t = std::function<std::shared_ptr<HttpResponse>(std::shared_ptr<HttpRequest>)>; // 请求处理函数类型

// HttpRequest类表示客户端的HTTP请求
class HttpRequest
{
private:
    // 从请求字符串中提取一行数据（以换行符分隔）
    std::string GetOneline(std::string &reqstr)
    {
        if (reqstr.empty()) return {};  // 如果请求字符串为空，返回空字符串
        auto pos = reqstr.find(sep);    // 查找换行符的位置
        if (pos == std::string::npos) return {};  // 如果找不到换行符，返回空

        std::string line = reqstr.substr(0, pos);  // 提取行
        reqstr.erase(0, pos + sep.size());         // 从请求字符串中删除已提取的部分
        return line;
    }

    // 辅助函数，解析请求头中的键值对（格式为 key: value）
    bool ParseHeaderHelper(const std::string &line, std::string &k, std::string &v)
    {
        auto pos = line.find(header_sep);          // 查找冒号和空格的分隔符
        if (pos == std::string::npos) return false; // 如果找不到分隔符，解析失败

        k = line.substr(0, pos);                   // 提取key
        v = line.substr(pos + header_sep.size());  // 提取value
        return true;
    }

    // 解析HTTP请求行，提取方法、URL、版本等信息
    bool ParseReqLine()
    {
        if (_req_line.empty()) return false;

        std::stringstream ss(_req_line);  // 使用字符串流解析请求行
        ss >> _method >> _url >> _version;  // 提取HTTP方法、URL和版本

        // 如果请求方法是GET，处理URL中的查询参数
        if (_method == "GET" || _method == "get")
        {
            auto pos = _url.find(args_sep);
            if (pos != std::string::npos)
            {
                LOG(INFO, "change begin, url: %s\n", _url.c_str());
                _args = _url.substr(pos + args_sep.size());  // 提取查询参数
                _url.resize(pos);  // 只保留URL部分
                LOG(INFO, "change done, url: %s, _args: %s\n", _url.c_str(), _args.c_str());
            }
        }

        _path += _url;  // 将根目录加上URL形成路径

        // 如果路径以'/'结尾，则表示请求根目录，加载默认的首页文件
        if (_path.back() == '/')
        {
            _path += homepage;
        }

        // 解析文件后缀，用于MIME类型判断
        auto pos = _path.rfind(filesuffixsep);
        _suffix = (pos == std::string::npos) ? ".unknown" : _path.substr(pos + filesuffixsep.size());

        LOG(INFO, "client requested %s, _suffix: %s\n", _path.c_str(), _suffix.c_str());
        return true;
    }

    // 解析HTTP请求头，将每个键值对存入_headers映射
    bool ParseHeader()
    {
        for (const auto &header : _req_header)
        {
            std::string k, v;
            if (ParseHeaderHelper(header, k, v))
            {
                _headers[k] = v;  // 将键值对存入_headers
            }
        }
        return true;
    }

public:
    // HttpRequest构造函数，初始化一些基本成员变量
    HttpRequest() : _blank_line(sep), _path(wwwroot) {}

    // 反序列化请求字符串，将其解析为请求行、请求头等部分
    void Derialize(std::string &reqstr)
    {
        _req_line = GetOneline(reqstr);  // 提取请求行
        while (true)
        {
            std::string line = GetOneline(reqstr);  // 逐行提取请求头
            if (line.empty()) break;

            _req_header.emplace_back(line);  // 将请求头行保存
        }

        ParseReqLine();  // 解析请求行
        ParseHeader();   // 解析请求头
    }

    // 打印请求内容，用于调试
    void Print() const
    {
        std::cout << "===" << _req_line << std::endl;
        for (const auto &header : _req_header) std::cout << "***" << header << std::endl;
        std::cout << _blank_line;
        std::cout << _req_text << std::endl;
        std::cout << "method ### " << _method << std::endl;
        std::cout << "url ### " << _url << std::endl;
        std::cout << "path ### " << _path << std::endl;
        std::cout << "httpversion ### " << _version << std::endl;
        for (const auto &header : _headers) std::cout << "@@@" << header.first << " - " << header.second << std::endl;
    }

    // 一些公开接口，用于获取请求的路径、后缀、参数等信息
    std::string Path() const { return _path; }
    std::string Suffix() const { return _suffix; }
    bool IsExec() const { return !_args.empty() || !_req_text.empty(); }
    std::string Args() const { return _args; }
    std::string Text() const { return _req_text; }
    std::string Method() const { return _method; }

private:
    // 内部成员变量，存储请求行、请求头、请求体等内容
    std::string _req_line;
    std::vector<std::string> _req_header;
    std::string _blank_line;
    std::string _req_text;

    std::string _method;
    std::string _url;
    std::string _args;
    std::string _path;
    std::string _suffix;
    std::string _version;

    std::unordered_map<std::string, std::string> _headers;  // 请求头键值对
};

// HttpResponse类表示HTTP响应
class HttpResponse
{
public:
    HttpResponse() : _version(httpversion), _blank_line(sep) {}

    // 添加状态行（HTTP版本、状态码、描述）
    void AddStatusLine(int code, const std::string &desc)
    {
        _code = code;
        _desc = desc;
    }

    // 添加HTTP响应头
    void AddHeader(const std::string &k, const std::string &v)
    {
        _headers[k] = v;
    }

    // 添加响应正文
    void AddText(const std::string &text)
    {
        _resp_text = text;
    }

    // 序列化响应，将状态行、响应头、正文拼接成字符串
    std::string Serialize()
    {
        std::string status_line = _version + space + std::to_string(_code) + space + _desc + sep;
        for (const auto &header : _headers)
        {
            _resp_header.emplace_back(header.first + header_sep + header.second + sep);
        }
        std::string response = status_line;
        for (const auto &header : _resp_header)
        {
            response += header;
        }
        response += _blank_line + _resp_text;
        return response;
    }

private:
    std::string _version;
    int _code;
    std::string _desc;
    std::unordered_map<std::string, std::string> _headers;

    std::string _blank_line;
    std::vector<std::string> _resp_header;
    std::string _resp_text;
};

// Factory类，用于生成HttpRequest和HttpResponse对象
class Factory
{
public:
    static std::shared_ptr<HttpRequest> BuildHttpRequest()
    {
        return std::make_shared<HttpRequest>();
    }

    static std::shared_ptr<HttpResponse> BuildHttpResponse()
    {
        return std::make_shared<HttpResponse>();
    }
};

// HttpServer类，处理HTTP请求并生成响应
class HttpServer
{
public:
    HttpServer()
    {
        // 初始化MIME类型和状态码描述
        _mime_type = {
            {".html", "text/html"},
            {".css", "text/css"},
            {".js", "application/x-javascript"},
            {".png", "image/png"},
            {".jpg", "image/jpeg"},
            {".unknown", "text/html"}
        };

        _code_to_desc = {
            {100, "Continue"},
            {200, "OK"},
            {301, "Moved Permanently"},
            {302, "Found"},
            {404, "Not Found"},
            {500, "Internal Server Error"}
        };
    }

    // 添加请求处理函数
    void AddHandler(const std::string &functionname, func_t f)
    {
        _funcs[wwwroot + functionname] = f;
    }

    // 读取文件内容，用于处理静态文件请求
    std::string ReadFileContent(const std::string &path, int &size)
    {
        std::ifstream in(path, std::ios::binary);
        if (!in.is_open())
        {
            return {};
        }

        in.seekg(0, in.end);
        size = in.tellg();  // 获取文件大小
        in.seekg(0, in.beg);

        std::string content(size, '\0');
        in.read((char *)content.c_str(), size);  // 读取文件内容
        in.close();
        return content;
    }

    // 处理HTTP请求并生成响应
    std::string HandleHttpRequest(const std::string &req)
    {
        std::cout << "\n原始请求数据: \n" << req << "*****************************" << std::endl;
        
        auto request = Factory::BuildHttpRequest();  // 创建HttpRequest对象
        request->Derialize(const_cast<std::string&>(req));  // 反序列化请求

        std::cout << "反序列化提取后：" << std::endl;
        request->Print();

        auto response = Factory::BuildHttpResponse();  // 创建HttpResponse对象
        std::string newurl = "https://www.baidu.com/";
        int code = 200;

        // 处理重定向请求
        if (request->Path() == "wwwroot/redir")
        {
            code = 301;
            response->AddStatusLine(code, _code_to_desc[code]);
            response->AddHeader("Location", newurl);
        }
        // 处理可执行请求（带有参数或请求体）
        else if (request->IsExec())
        {
            auto handler_response = _funcs[request->Path()](request);
            return handler_response->Serialize();
        }
        // 处理静态文件请求
        else
        {
            int contentsize = 0;
            std::string text = ReadFileContent(request->Path(), contentsize);  // 读取文件
            if (text.empty())
            {
                code = 404;
                text = ReadFileContent("wwwroot/404.html", contentsize);  // 文件未找到，返回404页面
            }
            response->AddStatusLine(code, _code_to_desc[code]);  // 添加状态行
            response->AddHeader("Content-Length", std::to_string(contentsize));  // 添加内容长度头
            response->AddText(text);  // 添加响应正文
            response->AddHeader("Content-Type", _mime_type[request->Suffix()]);  // 根据后缀设置MIME类型
        }
        return response->Serialize();  // 返回序列化的响应
    }

private:
    std::unordered_map<std::string, std::string> _mime_type;  // MIME类型映射
    std::unordered_map<int, std::string> _code_to_desc;  // 状态码到描述的映射
    std::unordered_map<std::string, func_t> _funcs;  // URL路径到处理函数的映射
};
